package lxs.tool.liberator.work.service.imp;

import lxs.tool.liberator.common.base.result.Response;
import lxs.tool.liberator.common.utils.IDCreator;
import lxs.tool.liberator.system.config.DynamicDataSource;
import lxs.tool.liberator.work.mapper.ClassMapper;
import lxs.tool.liberator.work.mapper.ColumnMapper;
import lxs.tool.liberator.work.mapper.ProjectMapper;
import lxs.tool.liberator.work.pojo.Class;
import lxs.tool.liberator.work.pojo.Column;
import lxs.tool.liberator.work.pojo.Project;
import lxs.tool.liberator.work.service.ClassService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

@Service("ClassServiceImp")
public class ClassServiceImp implements ClassService {
    @Autowired
    private ClassMapper classMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private ColumnMapper columnMapper;
    @Autowired
    private DynamicDataSource dbSourceService;

    private static final String insert = "INSERT INTO `[tableName]` ([columns]) VALUES ([values]);";
    private static final String chars = "0123456789abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ";
    private static final Random random = new Random();

    @Override
    public Response showTable() {
        Project mainProject = projectMapper.getMainProject();
        return Response.send(classMapper.showTable(mainProject.getId()));
    }

    @Override
    public Response getOptions() {
        Project mainProject = projectMapper.getMainProject();
        return Response.send(classMapper.getOptions(mainProject.getId()));
    }

    @Override
    public Response getMeta() throws SQLException {
        Project mainProject = projectMapper.getMainProject();
        dbSourceService.switchTo(mainProject);
        List<Class> classes = classMapper.getMeta(mainProject.getDbname());
        auto(classes, mainProject.getId());
        dbSourceService.switchBack();
        return Response.success();
    }

    @Override
    public Response clear(String className) throws SQLException {
        Project mainProject = projectMapper.getMainProject();
        dbSourceService.switchTo(mainProject);
        dbSourceService.execute("delete from " + "`" + className + "`");
        dbSourceService.switchBack();
        return Response.success();
    }

    @Override
    public Response updateJavaName(String name, String id) {
        classMapper.updateJavaName(name, id);
        return Response.success();
    }

    @Override
    public Response updateIdColumn(String idColumn, String id) {
        classMapper.updateIdColumn(idColumn, id);
        return Response.success();
    }

    @Override
    public Response updateCount(String id) throws SQLException {
        Class aClass = classMapper.selectById(id);
        Project mainProject = projectMapper.getMainProject();
        dbSourceService.switchTo(mainProject);
        ResultSet resultSet = dbSourceService.executeQuery(" select count(1) from " + "`" + aClass.getNameInDb() + "`");
        resultSet.next();
        int integer = Integer.parseInt(resultSet.getString(1));
        dbSourceService.switchBack();
        classMapper.setCount(id, integer);
        return Response.success();
    }

    @Override
    public Response buildData(String classId, Integer count) throws Exception {
        List<String> columns = new ArrayList<>();
        List<String> values = new ArrayList<>();
        List<Column> columnList = columnMapper.getListByClassId(classId);
        Class aClass = classMapper.selectById(classId);
        for (Column c : columnList) {
            columns.add("`" + c.getColumnName() + "`");
            String linkColumnId = c.getLinkColumnId();
            if (StringUtils.isNotEmpty(linkColumnId)) {
                Column column = columnMapper.selectById(linkColumnId);
                if (column.getClassId().equals(c.getClassId())) continue;
                Class linkClass = classMapper.selectById(column.getClassId());
                updateCount(linkClass.getId());
                if (linkClass.getDataCount().equals("0")) {
                    throw new Exception("请先生成关联的 " + c.getColumnName() + " 字段所在的表 " + linkClass.getNameInDb() + " 的数据");
                }
            }
        }
        String cs = StringUtils.join(columns, ",");
        String sql = insert;
        sql = sql.replace("[tableName]", aClass.getNameInDb());
        sql = sql.replace("[columns]", cs);
        Project mainProject = projectMapper.getMainProject();
        List<String> sqlList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            for (Column c : columnList) {
                if (StringUtils.isNotEmpty(c.getLinkColumnId())) {
                    Column linkColumn = columnMapper.selectById(c.getLinkColumnId());
                    Class linkClass = classMapper.selectById(linkColumn.getClassId());
                    int dataCount = classMapper.getCount("`" + linkClass.getNameInDb() + "`");
                    if (dataCount == 0) {
                        values.add("''");
                    } else {
                        if (randNumber(0, 6) < 2 && linkClass.getId().equals(c.getClassId())) {
                            values.add("''");
                        } else {
                            int rand = randNumber(0, dataCount - 1);
                            String s = classMapper.randomGetOneByTableAndColumn("`" + linkClass.getNameInDb() + "`",
                                    "`" + linkColumn.getColumnName() + "`",
                                    rand);
                            values.add("'" + s + "'");
                        }
                    }
                } else values.add("'" + randomData(c.getValueRule()) + "'");
            }
            String vs = StringUtils.join(values, ",");
            String s = sql.replace("[values]", vs);
            sqlList.add(s);
            values.clear();
        }
        dbSourceService.switchTo(mainProject);
        for (String s : sqlList) {
            dbSourceService.execute(s);
        }
        dbSourceService.switchBack();
        return Response.success();
    }

    /**
     * 将从元数据中查出来的信息自动入表
     *
     * @param classes
     * @param pid
     */
    private void auto(List<Class> classes, String pid) {
        List<String> names = new ArrayList<>();
        for (Class c : classes) {
            names.add(c.getNameInDb());
        }
        classMapper.deleteByProjectIdAndUnExist(pid, names);
        for (Class c : classes) {
            c.setId(IDCreator.get("class"));
            c.setProjectId(pid);
            try {
                classMapper.insert(c);
                updateCount(c.getId());
            } catch (Exception e) {
                String existId = classMapper.getTheExistId(c.getProjectId(), c.getNameInDb());
                c.setId(existId);
                classMapper.updateById(c);
            }
        }
    }

    private String randomData(String rule) {
        if (rule.matches("\\(.+\\)")) {
            String[] split = rule.substring(1, rule.length() - 1).split("\\|");
            return split[random.nextInt(split.length)];
        } else {
            StringBuilder re = new StringBuilder();
            String left;
            int right;
            String str;
            String[] split = rule.split("&&");
            for (String s : split) {
                right = Integer.parseInt(s.substring(s.indexOf("{") + 1, s.length() - 1));
                if (right > 500) {
                    right = 500;
                }
                for (int i = 0; i < right; i++) {
                    char l = s.charAt(1);
                    char r = s.charAt(3);
                    if (s.contains("[a-Z]{") || s.contains("[A-z]{")) {
                        str = chars.charAt(randNumber(10, chars.length()-1)) + "";
                    } else if (!charType(l).equals(charType(r))) {
                        int li = chars.indexOf(l);
                        int ri = chars.indexOf(r);
                        str = chars.charAt(randNumber(Math.min(li, ri), Math.max(li, ri))) + "";
                    } else if (s.matches("\\[.+-.+]\\{[0-9]+}") && !s.contains("[.-.]{")) {
                        char c = (char) (randNumber(l, r));
                        str = c + "";
                    } else if (s.matches("<.+>\\{[0-9]+}")) {
                        left = s.substring(1, s.lastIndexOf(">"));
                        str = left;
                    } else {
                        char c = (char) (randNumber(19968, 30000));
                        str = c + "";
                    }
                    re.append(str);
                }
            }
            return re.toString();
        }
    }

    private int randNumber(int min, int max) {
        return random.nextInt(max - min + 1) + min;
    }

    private String charType(char c) {
        if (Character.isDigit(c)) return "number";
        if (Character.isLowerCase(c)) return "low";
        if (Character.isUpperCase(c)) return "up";
        if (c >= 19968 && c <= 40869) return "chinese";
        return "else";
    }
}
